package com.htthorizon.gateway.handler;

import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.htthorizon.common.core.utils.JwtUtils;
import com.htthorizon.common.core.utils.ServletUtils;
import com.htthorizon.common.core.utils.StringUtils;
import com.htthorizon.common.core.utils.ip.IpUtils;
import com.htthorizon.common.redis.service.RedisService;
import com.htthorizon.system.api.domain.SysLogininfor;
import com.htthorizon.system.api.domain.SysOperLog;
import com.htthorizon.system.api.exception.KeyNotException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author Brilliant
 */

@Slf4j
@Component
public class RequestGlobalFilter implements GlobalFilter, Ordered {

    @Value("${unique}")
    private boolean unique;

    @Autowired
    private RedisService redisService;

    public static int[] twoSum(int[] nums, int target) {
        int[] result=new int[2];
        Map<Integer,Integer> map=new HashMap<>(nums.length);
        for (int i=0;i<nums.length;i++){
            if (map.containsKey(target-nums[i])){
                result[0]=map.get(target-nums[i]);
                result[1]=i;
                return result;
            }
            map.put(nums[i],i);
        }
        return result;
    }

    public static void main(String[] args) {
       int[] i= new int[]{3,2,4};
        int[] ints = twoSum(i, 6);
        System.out.println(ints[0]);
        System.out.println(ints[1]);
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        String method = request.getMethodValue();
        String first = request.getHeaders().getFirst("x-Forwarded-For");
        HttpHeaders headers1 = request.getHeaders();
        List<String> list1 = headers1.get("authorization");
        String userName1;
        if (!Objects.isNull(list1) &&!(list1.isEmpty())){
            String token = list1.get(0);
            userName1 = JwtUtils.getUserName(token);
        } else {
            userName1 = null;
        }
        if (!unique){
            return chain.filter(exchange);
        }


        SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, "KWCNJQWNUAOW8E19".getBytes());
        if (
//                request.getURI().getPath().contains("login")
                request.getURI().getPath().contains("upload")
//                ||request.getURI().getPath().contains("ims")
//                ||request.getURI().getPath().contains("getDept")
//                ||request.getURI().getPath().contains("logout")
//                ||request.getURI().getPath().contains("crossAudit/del")
////                ||request.getURI().getPath().contains("user/del")
//                request.getURI().getPath().contains("download")
                ){
            return chain.filter(exchange);
        }
//        if (request.getURI().getPath().contains("upload")){
//            return DataBufferUtils.join(exchange.getRequest().getBody())
//                    .flatMap(dataBuffer -> {
//                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
//                        dataBuffer.read(bytes);
//                        String bodyString = new String(bytes, StandardCharsets.UTF_8);
//                        String s = request.getHeaders().get("paramsString").get(0);
//
//                        String s1 = DigestUtil.md5Hex16(bodyString);
//
//                        if (!s.equals(s1)){
//                            SysOperLog sysLogininfor = SysOperLog.build(userName1, IpUtils.getIpAddr1( exchange.getRequest()), "会话篡改",request.getMethod().toString(),path,request);
//                            redisService.setCacheObject("log:"+sysLogininfor.getCreateTime(),sysLogininfor);
//                            throw new KeyNotException();
//                        }
//                        exchange.getAttributes().put("POST_BODY", bodyString);
//                        DataBufferUtils.release(dataBuffer);
//
//                        Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
//                            DataBuffer buffer = exchange.getResponse().bufferFactory()
//                                    .wrap(bytes);
//                            return Mono.just(buffer);
//                        });
//                        //下面的将请求体再次封装写回到request里，传到下一级，否则，由于请求体已被消费，后续的服务将取不到值
//                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
//                                exchange.getRequest()) {
//                            @Override
//                            public Flux<DataBuffer> getBody() {
//                                return cachedFlux;
//                            }
//                        };
//                        //封装request，传给下一级
//                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
//                    });
//        }



        if ("POST".equals(method)) {
            if(headers1.getContentLength()>0|| headers1.getContentType() != null){
                return DataBufferUtils.join(exchange.getRequest().getBody())
                        .flatMap(dataBuffer -> {
                            byte[] bytes = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(bytes);
                            String bodyString = new String(bytes, StandardCharsets.UTF_8);
                            String s = request.getHeaders().get("paramsString").get(0);

                            String s1 = aes.decryptStr(s);

                            try {
                                List<String> list = headers1.get("paramsString");
                                String ss = list.get(0);
                                if (StringUtils.isEmpty(ss)){
                                    throw new RuntimeException("缺少paramsString");
                                }
                                String cacheObject = redisService.getCacheObject(path + ss);
                                if (cacheObject !=null){
                                    SysOperLog sysLogininfor = SysOperLog.build(userName1, IpUtils.getIpAddr1( exchange.getRequest()), "重复请求",request.getMethod().toString(),path,request);
                                    redisService.setCacheObject("log:"+sysLogininfor.getCreateTime(),sysLogininfor);
                                    throw new KeyNotException();
                                }
                                redisService.setCacheObject(path+ss,"time", 100L, TimeUnit.SECONDS);
                            }catch (NullPointerException e){

                            }
                            JSONObject objects = new JSONObject(s1);
                            if (StringUtils.isEmpty(s)){
                                throw new KeyNotException();
                            }
                            boolean equals=true;
                            if ( !request.getURI().getPath().contains("login")){
                                JSONObject objects2 = new JSONObject(bodyString);
                                equals = objects2.equals(objects);
                            }else {
                                System.out.println(bodyString);
                                System.out.println("//////");
                                System.out.println(objects);
                            }

                            if (!equals){

                                SysOperLog sysLogininfor = SysOperLog.build(userName1, IpUtils.getIpAddr1( exchange.getRequest()), "会话篡改",request.getMethod().toString(),path,request);
                                redisService.setCacheObject("log:"+sysLogininfor.getCreateTime(),sysLogininfor);
                                throw new KeyNotException();
                            }
                            exchange.getAttributes().put("POST_BODY", bodyString);
                            DataBufferUtils.release(dataBuffer);

                            Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                                DataBuffer buffer = exchange.getResponse().bufferFactory()
                                        .wrap(bytes);
                                return Mono.just(buffer);
                            });
                            //下面的将请求体再次封装写回到request里，传到下一级，否则，由于请求体已被消费，后续的服务将取不到值
                            ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                    exchange.getRequest()) {
                                @Override
                                public Flux<DataBuffer> getBody() {
                                    return cachedFlux;
                                }
                            };
                            //封装request，传给下一级
                            return chain.filter(exchange.mutate().request(mutatedRequest).build());
                        });
            }else {
                return chain.filter(exchange);
            }

        } else if ("GET".equals(method)) {
            return chain.filter(exchange);
        }
        return chain.filter(exchange);
    }


    /**
     * 执行顺序
     *
     * @return
     */
    @Override
    public int getOrder() {
        return 1;
    }

}